import logging
from datetime import datetime, time, timedelta

from core.constant import Status as OrderStatus
from event import Event
from gateway.base_gateway import BaseGateway
from .base_fucker import BaseFucker
from .base_fucker import FuckerStatus

logger = logging.getLogger('fucker')


class SmartFucker(BaseFucker):
    def __init__(self, gateway: BaseGateway, **kwargs):
        super().__init__(gateway,**kwargs)

        self.default_start_time = datetime.now()
        # 全局结束时间.默认start_time+1分钟
        self.default_end_time = self.default_start_time + timedelta(minutes=10)

        self.time_slice = kwargs.get('time_slice', 3)
        self.cancel_wait_time = kwargs.get('cancel_wait_time', 10)
        self.max_order_vol = kwargs.get('max_order_vol', 168)
        self.print_tick = kwargs.get('print_tick', False)

    def on_tick(self, e: Event):
        tick = e.data
        if self.print_tick:
            logger.debug(tick)

        if self.status != FuckerStatus.RUNNING:
            return

        tick_time = tick.datetime.time()

        if tick_time < time(9, 0) or time(16, 0) < tick_time < time(21, 0):
            return

        vt_symbol = tick.vt_symbol

        if self.finished[vt_symbol]:
            return

        now = datetime.now()
        # 标的开始时间,配置了使用配置时间。没有配置使用默认时间
        if self.trade_time_table is not None and vt_symbol in self.trade_time_table.index:
            self.start_time = self.trade_time_table.loc[vt_symbol]['start_time']
            self.end_time = self.trade_time_table.loc[vt_symbol]['end_time']
        else:
            logger.warning(f'{vt_symbol=} 初始化时间表失败,不交易。')
            return

        if now < self.start_time:
            if now.second % 5 == 0:
                logger.debug(f'{vt_symbol=},开始时间为{self.start_time=}')
            return

        if self.change_pos[vt_symbol] > 0:
            if 1e10 > tick.bid_price_1 > 0:
                price = tick.bid_price_1
                if abs(price - tick.low_price) < 1e-10 and abs(price - tick.high_price) > 1e-10:
                    logger.info(f'{vt_symbol} try to long at low')
                    return
            else:
                return
        else:
            if 1e10 > tick.ask_price_1 > 0:
                price = tick.ask_price_1
                if abs(price - tick.high_price) < 1e-10 and abs(price - tick.low_price) > 1e-10:
                    logger.debug(f'{vt_symbol} try to short at high')
                    return
            else:
                return
        self.check_cancel_orders(vt_symbol, price)

        target_pos = self.target_pos.get(vt_symbol, 0)
        current_pos = self.position_management.get_position_holding(vt_symbol).current_pos

        if target_pos * current_pos <= -1:
            target_pos = 0

        pos_dif = target_pos - current_pos

        trading_pos = self.position_management.get_position_holding(vt_symbol).trading_pos

        logger.info(
            f'symbol: {vt_symbol}, target: {target_pos}, current: {current_pos}, trading: {trading_pos} ,pos_diff:{pos_dif}')

        if pos_dif == 0:
            if trading_pos != 0:
                logger.warning('target == current but trading != 0')
            return

        to_trade = pos_dif - trading_pos
        logger.debug(f'vt_symbol:{vt_symbol},to_trade:{to_trade}')
        # self.change_pos[vt_symbol] = self.reset_open_pos(vt_symbol, to_trade)
        if (self.change_pos[vt_symbol] < 0 and to_trade < 0) or (self.change_pos[vt_symbol] > 0 and to_trade > 0):

            to_trade = self.max_order_vol_cons(vt_symbol, to_trade, now)

            logger.debug(f'vt_symbol:{vt_symbol},order_vol_cons_to_trade:{to_trade}')
            if to_trade != 0:
                self.send_net_pos_order(vt_symbol, price, to_trade)
        else:
            logger.debug(f'vt_symbol:{vt_symbol},self.change_pos[vt_symbol] :{self.change_pos[vt_symbol]}')

    def max_order_vol_cons(self, vt_symbol, vol, now):
        all_to_trade = self.change_pos[vt_symbol]
        left_time = int((self.end_time - now).total_seconds() / self.time_slice) * self.time_slice

        if left_time < 0 or self.end_time <= self.start_time:
            return vol

        left_pct = left_time / (self.end_time - self.start_time).total_seconds()

        no_trade = int(all_to_trade * left_pct)

        if vol > 0:
            if vol <= no_trade:
                return 0
            else:
                return vol - no_trade
        else:
            if vol >= no_trade:
                return 0
            else:
                return vol - no_trade

    def check_cancel_orders(self, vt_symbol, price):
        for order in self.position_management.get_position_holding(vt_symbol).active_orders.values():
            # logger.debug(f'order.price - price::{order.price=},{price},{order.price - price}')

            # 股指国债最小变动 0.01，商品变化0.1
            unit = 0.01 if vt_symbol.endswith('.CFFEX') else 0.1

            if abs(order.price - price) >= unit:
                # logger.debug(f'order.status::{order.status}')

                if order.status != OrderStatus.INIT:
                    now = datetime.now()
                    ot = datetime.strptime(order.time, '%H:%M:%S')
                    ot = ot.replace(year=now.year, month=now.month, day=now.day)
                    # logger.debug(
                    #     f'(now - ot).total_seconds() > self.cancel_wait_time::{(now - ot).total_seconds() > self.cancel_wait_time}')
                    if (now - ot).total_seconds() > self.cancel_wait_time:
                        self.cancel_order(order)
